package org.openarchitectureware.adapter.rsdp.workflow;

import java.io.File;
import java.net.URI;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.eclipse.emf.ecore.EPackage;
import org.eclipse.emf.mwe.core.WorkflowComponent;
import org.eclipse.emf.mwe.core.WorkflowContext;
import org.eclipse.emf.mwe.core.container.CompositeComponent;
import org.eclipse.emf.mwe.core.issues.Issues;
import org.eclipse.emf.mwe.core.monitor.ProgressMonitor;
import org.eclipse.emf.mwe.internal.core.ast.parser.Location;
import org.eclipse.xtend.typesystem.emf.Mapping;
import org.eclipse.xtend.typesystem.uml2.Setup;

public class RSASetup extends Setup implements WorkflowComponent {
	private static final String COMPONENT_NAME = "RSA Setup";

	private CompositeComponent container;

	private List<UmlExtensionProject> extensionProjects = new ArrayList<UmlExtensionProject>();

	private List<PathMapEntry> pathMapEntries = new ArrayList<PathMapEntry>();

	private static Log logger = LogFactory.getLog(RSASetup.class);

	private Location location = null;

	/**
	 * Register a plugin containing uml2 / rsa profiles.
	 * 
	 * @param plugin
	 *            plugin to register
	 */
	public void addUmlExtensionProject(UmlExtensionProject plugin) {
		extensionProjects.add(plugin);
	}

	/**
	 * Adds a path map entry.
	 * 
	 * @param pathMapEntry
	 *            the path map entry.
	 */
	public void addPathMapEntry(PathMapEntry pathMapEntry) {
		pathMapEntries.add(pathMapEntry);
	}

	/**
	 * @see org.openarchitectureware.workflow.WorkflowComponent#checkConfiguration(org.openarchitectureware.workflow.issues.Issues)
	 */
	public void checkConfiguration(Issues issues) {
	}

	/**
	 * @see org.openarchitectureware.workflow.WorkflowComponent#getContainer()
	 */
	public CompositeComponent getContainer() {
		return container;
	}

	/**
	 * @see org.openarchitectureware.workflow.WorkflowComponent#invoke(org.openarchitectureware.workflow.WorkflowContext,
	 *      org.openarchitectureware.workflow.monitor.ProgressMonitor,
	 *      org.openarchitectureware.workflow.issues.Issues)
	 */
	public void invoke(WorkflowContext ctx, ProgressMonitor monitor, Issues issues) {
	}

	/**
	 * Registers all necessary resources.
	 * 
	 * @param b
	 *            Initialization occurs only if <code>true</code> is passed.
	 */
	public void setInit(boolean b) {
		super.setStandardUML2Setup(b);

		// Add RSA/RSM specific uml file extensions
		addExtensionMap(new Mapping("emx", "org.eclipse.uml2.uml.resource.UMLResource"));
		addExtensionMap(new Mapping("epx", "org.eclipse.uml2.uml.resource.UMLResource"));

		// Add plugins containing profiles or type libraries
		addUriMaps(extensionProjects);

		// Add pathmap entry
		addUriMaps(pathMapEntries);
		
		// Add GMF and IBM stuff
		try {
			EPackage.Registry.INSTANCE.put("http://www.eclipse.org/gmf/runtime/1.0.0/notation", EPackage.Registry.INSTANCE.get(org.eclipse.gmf.runtime.notation.NotationPackage.eINSTANCE.getNsURI()));
			EPackage.Registry.INSTANCE.put("http://www.eclipse.org/gmf/runtime/1.0.1/notation", EPackage.Registry.INSTANCE.get(org.eclipse.gmf.runtime.notation.NotationPackage.eINSTANCE.getNsURI()));
			EPackage.Registry.INSTANCE.put("http://www.eclipse.org/gmf/runtime/1.0.2/notation", EPackage.Registry.INSTANCE.get(org.eclipse.gmf.runtime.notation.NotationPackage.eINSTANCE.getNsURI()));
		} catch (NoClassDefFoundError e) {
			logger.warn("GMF runtime notation not initialized, missing in classpath");
		}
		
		try {
			EPackage.Registry.INSTANCE.put("http://www.ibm.com/xtools/1.5.0/Umlnotation", EPackage.Registry.INSTANCE.get(com.ibm.xtools.umlnotation.UmlnotationPackage.eINSTANCE.getNsURI()));
			EPackage.Registry.INSTANCE.put("http://www.ibm.com/xtools/1.5.1/Umlnotation", EPackage.Registry.INSTANCE.get(com.ibm.xtools.umlnotation.UmlnotationPackage.eINSTANCE.getNsURI()));
			EPackage.Registry.INSTANCE.put("http://www.ibm.com/xtools/1.5.2/Umlnotation", EPackage.Registry.INSTANCE.get(com.ibm.xtools.umlnotation.UmlnotationPackage.eINSTANCE.getNsURI()));
		}
		catch (NoClassDefFoundError e) {
			logger.warn("IBM uml notation not initialized, missing in classpath");
		}
	}

	private void addUriMaps(List<? extends AbstractURIMapEntry> mapEntries) {
		for (Iterator<? extends AbstractURIMapEntry> ipp = mapEntries.iterator(); ipp.hasNext();) {
			AbstractURIMapEntry plugin = ipp.next();
			File location = new File(plugin.getPath());

			if (location.exists() == false || location.isDirectory() == false) {
				logger.error("Location " + location + " doesn't exist or is not a valid directory");
			}
			else {
				URI locationURI = location.toURI();
				String mappedURI = plugin.getMappedURI();

				addUriMap(new Mapping(mappedURI, locationURI.toString()));
				logger.info("Added URI mapping " + locationURI + " as " + mappedURI);
			}
		}
	}

	/**
	 * @see org.openarchitectureware.workflow.WorkflowComponent#setContainer(org.openarchitectureware.workflow.container.CompositeComponent)
	 */
	public void setContainer(CompositeComponent container) {
		this.container = container;
	}

	/**
	 * @see org.openarchitectureware.workflow.WorkflowComponent#getLocation()
	 */
	public Location getLocation() {
		return location;
	}

	/**
	 * @see org.openarchitectureware.workflow.WorkflowComponent#setLocation(org.openarchitectureware.workflow.ast.parser.Location)
	 */
	public void setLocation(Location location) {
		this.location = location;
	}

	/**
	 * @see org.openarchitectureware.workflow.WorkflowComponent#getComponentName()
	 */
	public String getComponentName() {
		return COMPONENT_NAME;
	}
}
